#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>

#include <err.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include <pthread.h>

#include "thread_data.h"

void *
process_client(void *arg)
{
	if (arg == NULL)
		pthread_exit(NULL);

	int client;
	sa_family_t family;

	char ip[INET6_ADDRSTRLEN];

	const void *src;

	struct thread_data *p = arg;
	client = p->fd;
	family = p->addr.ss_family;

	free(arg);

	switch (family) {
	case AF_INET:
		src = &((struct sockaddr_in *)&p->addr)->sin_addr;
		break;
	case AF_INET6:
		src = &((struct sockaddr_in6 *)&p->addr)->sin6_addr;
		break;
	default:
		warnx("unsupported address family %d", family);
		goto DONE;
	}

	if (inet_ntop(family, src, ip, sizeof(ip)) == NULL) {
		warn("inet_ntop");
		goto DONE;
	}

	for (;;) {
		char buff[80];
		ssize_t len;
		if ((len = recv(client, buff, sizeof(buff) - 1, 0)) == -1) {
			warn("recv");
			break;
		} else if (len == 0) {
			/* peer has closed its half side of the connection */
			if (shutdown(client, SHUT_WR) == -1)
				warn("shutdown");
			break;
		}

		/* truncate buffer */
		buff[len] = '\0';
		printf("%s says: %s", ip, buff);

		if (strncmp(buff, "bye", 3) == 0 ||
			strncmp(buff, "exit", 4) == 0 ||
			strncmp(buff, "quit", 4) == 0) {
			if (buff[3] == '\n' ||
				buff[3] == '\r' ||
				buff[4] == '\n' || buff[4] == '\r') {
				if (shutdown(client, SHUT_WR) == -1)
					warn("shutdown");
				break;
			}
		}

		if (send(client, buff, len, 0) == -1) {
			warn("send");
			continue;
		}
	}

DONE:
	close(client);
	pthread_exit(NULL);
}
